let FFmpeg = {
    name: "FFmpeg wasm"
}
FFmpeg.WebGL = (function () {
    "use strict";
    let WebGLRenderer = function (options) {
        this.gl = options.gl
        this.dst_width = options.width;
        this.dst_height = options.height;
        this.enabled = true
        this.hasTextureData = {}

        let gl = this.gl;
        if (options.renderTexture) {
            this.renderTexture = options.renderTexture
            this.fbo = gl.createFramebuffer()
            gl.bindTexture(gl.TEXTURE_2D, this.renderTexture)
            gl.bindFramebuffer(gl.FRAMEBUFFER, this.fbo)
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.renderTexture, 0);
            gl.bindFramebuffer(gl.FRAMEBUFFER, null)
            gl.bindTexture(gl.TEXTURE_2D, null)
        }
        {
            this.vertexBuffer = gl.createBuffer();
            const vertexCoords = new Float32Array([1, 1, 1, 0, 0, 1, 0, 0]);
            // var vertexCoords = new Float32Array([0, 0, 0, 1, 1, 0, 1, 1]);
            gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, vertexCoords, gl.STATIC_DRAW);
            gl.bindBuffer(gl.ARRAY_BUFFER, null);
        }
        {
            this.program = this.createProgram(
                WebGLRenderer.SHADER.VERTEX_IDENTITY,
                WebGLRenderer.SHADER.FRAGMENT_YUV_TO_RGBA
                // WebGLRenderer.SHADER.FRAGMENT_DEFAULT
            );
            this.vertexAttr = gl.getAttribLocation(this.program, "vertex");
            this.textureY = this.createTexture(0, "textureY");
            this.textureCb = this.createTexture(1, "textureCb");
            this.textureCr = this.createTexture(2, "textureCr");
        }

    }
    WebGLRenderer.prototype.render = function (y, u, v, y_size = 0, u_size = 0, v_size = 0) {
        if (!this.enabled) {
            return;
        }
        const gl = this.gl;
        {
            let w = this.width; //((this.width + 15) >> 4) << 4,
            const h = this.height;
            let w2 = w >> 1;
            const h2 = h >> 1;
            let w3 = w >> 1;
            const h3 = h >> 1;

            if (y_size > 0) {
                w = y_size
            }
            if (u_size > 0) {
                w2 = u_size
            }
            if (v_size > 0) {
                w3 = v_size
            }

            this.updateTexture(gl.TEXTURE0, this.textureY, w, h, y);
            this.updateTexture(gl.TEXTURE1, this.textureCb, w2, h2, u);
            this.updateTexture(gl.TEXTURE2, this.textureCr, w3, h3, v);
        }

        gl.useProgram(this.program);

        gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
        gl.enableVertexAttribArray(this.vertexAttr);
        gl.vertexAttribPointer(this.vertexAttr, 2, gl.FLOAT, false, 0, 0);

        if (this.fbo) {
            gl.bindFramebuffer(gl.FRAMEBUFFER, this.fbo)
        }
        gl.viewport(0, 0, this.dst_width, this.dst_height);
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
        if (this.fbo) {
            gl.bindFramebuffer(gl.FRAMEBUFFER, null)
        }

        gl.useProgram(null);
    }
    WebGLRenderer.prototype.destroy = function () {
        const gl = this.gl;
        this.deleteTexture(gl.TEXTURE0, this.textureY);
        this.deleteTexture(gl.TEXTURE1, this.textureCb);
        this.deleteTexture(gl.TEXTURE2, this.textureCr);
        gl.useProgram(null);
        gl.deleteProgram(this.program);
        gl.deleteProgram(this.loadingProgram);
        gl.bindBuffer(gl.ARRAY_BUFFER, null);
        gl.deleteBuffer(this.vertexBuffer);
        // this.canvas.remove();
    };
    WebGLRenderer.prototype.resize = function (width, height) {
        this.width = width | 0;
        this.height = height | 0;
        // this.canvas.width = this.width;
        // this.canvas.height = this.height;
        // this.gl.useProgram(this.program);
        // var codedWidth = ((this.width + 15) >> 4) << 4;
    };
    WebGLRenderer.prototype.createTexture = function (index, name) {
        var gl = this.gl;
        var texture = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, texture);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        gl.uniform1i(gl.getUniformLocation(this.program, name), index);
        return texture;
    };
    WebGLRenderer.prototype.createProgram = function (vsh, fsh) {
        var gl = this.gl;
        var program = gl.createProgram();
        gl.attachShader(program, this.compileShader(gl.VERTEX_SHADER, vsh));
        gl.attachShader(program, this.compileShader(gl.FRAGMENT_SHADER, fsh));
        gl.linkProgram(program);
        gl.useProgram(program);
        return program;
    };
    WebGLRenderer.prototype.compileShader = function (type, source) {
        var gl = this.gl;
        var shader = gl.createShader(type);
        gl.shaderSource(shader, source);
        gl.compileShader(shader);
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
            throw new Error(gl.getShaderInfoLog(shader));
        }
        return shader;
    };
    WebGLRenderer.prototype.updateTexture = function (unit, texture, w, h, data) {
        const gl = this.gl;
        gl.activeTexture(unit);
        gl.bindTexture(gl.TEXTURE_2D, texture);
        if (this.hasTextureData[unit]) {
            gl.texSubImage2D(
                gl.TEXTURE_2D,
                0,
                0,
                0,
                w,
                h,
                gl.LUMINANCE,
                gl.UNSIGNED_BYTE,
                data
            );
        } else {
            this.hasTextureData[unit] = true;
            gl.texImage2D(
                gl.TEXTURE_2D,
                0,
                gl.LUMINANCE,
                w,
                h,
                0,
                gl.LUMINANCE,
                gl.UNSIGNED_BYTE,
                data
            );
        }
    };
    WebGLRenderer.prototype.deleteTexture = function (unit, texture) {
        var gl = this.gl;
        gl.activeTexture(unit);
        gl.bindTexture(gl.TEXTURE_2D, null);
        gl.deleteTexture(texture);
    };
    WebGLRenderer.SHADER = {
        FRAGMENT_DEFAULT: [
            "precision mediump float;",
            "uniform sampler2D textureY;",
            "uniform sampler2D textureCb;",
            "uniform sampler2D textureCr;",
            "varying vec2 texCoord;",
            "void main() {",
            "gl_FragColor = texture2D(textureY, texCoord);",
            "}",
        ].join("\n"),
        FRAGMENT_YCRCB_TO_RGBA: [
            "precision mediump float;",
            "uniform sampler2D textureY;",
            "uniform sampler2D textureCb;",
            "uniform sampler2D textureCr;",
            "varying vec2 texCoord;",
            "mat4 rec601 = mat4(",
            "1.16438,  0.00000,  1.59603, -0.87079,",
            "1.16438, -0.39176, -0.81297,  0.52959,",
            "1.16438,  2.01723,  0.00000, -1.08139,",
            "0, 0, 0, 1",
            ");",
            "void main() {",
            "float y = texture2D(textureY, texCoord).r;",
            "float cb = texture2D(textureCb, texCoord).r;",
            "float cr = texture2D(textureCr, texCoord).r;",
            "gl_FragColor = vec4(y, cr, cb, 1.0) * rec601;",
            "}",
        ].join("\n"),
        FRAGMENT_YUV_TO_RGBA: [
            "precision mediump float;",
            "uniform sampler2D textureY;",
            "uniform sampler2D textureCb;",
            "uniform sampler2D textureCr;",
            "varying vec2 texCoord;",
            "vec4 yuv_2_rgb(vec2 uv) {",
            "float y = texture2D(textureY, uv).r - 16.0/256.0;",
            "float u = texture2D(textureCb, uv).r - 128.0/256.0;",
            "float v = texture2D(textureCr, uv).r - 128.0/256.0;",
            "return vec4(1.164*y+1.596*v, 1.164*y-0.392*u-0.813*v, 1.164*y+2.017*u, 1.0);",
            // "return vec4(y,y,y, 1.0);",
            "}",
            "void main() {",
            "float scale = 0.00;",
            "vec4 col = yuv_2_rgb(texCoord+vec2(scale,scale));",
            "col += yuv_2_rgb(texCoord+vec2(scale,-scale));",
            "col += yuv_2_rgb(texCoord+vec2(-scale,scale));",
            "col += yuv_2_rgb(texCoord+vec2(-scale,-scale));",
            "col += yuv_2_rgb(texCoord);",
            "gl_FragColor = col/5.0/2.0;",
            "gl_FragColor = yuv_2_rgb(texCoord);",
            "}",
        ].join("\n"),
        VERTEX_IDENTITY: [
            "attribute vec2 vertex;",
            "varying vec2 texCoord;",
            "void main() {",
            "texCoord = vertex;",
            "gl_Position = vec4((vertex * 2.0 - 1.0) * vec2(1, -1), 0.0, 1.0);",
            "}",
        ].join("\n"),
    };
    return WebGLRenderer
})()